package io.shuttle.mbe.api

import io.shuttle.mbe.api.annotation.ChromeMinVersion
import io.shuttle.mbe.api.annotation.ChromeOSOnly
import io.shuttle.mbe.api.annotation.PromiseStyleMinVersion
import io.shuttle.mbe.api.types.ArrayBuffer
import io.shuttle.mbe.api.types.StrNumBoolOrNumArr
import io.shuttle.mbe.api.types.StringOrNumber
import io.shuttle.mbe.api.types.Value1Function
import io.shuttle.mbe.core.JSObject
import io.shuttle.mbe.core.Promise

////////////////////
// Document Scan
////////////////////
/**
 * Use the `Browser.documentScan` API to discover and retrieve images from attached document scanners.
 * The Document Scan API is designed to allow apps and extensions to view the content of paper documents on an attached document scanner.
 *
 * Permissions: "documentScan"
 * @platform ChromeOS only
 * @since Chrome 44
 */
@ChromeMinVersion(44)
@ChromeOSOnly
interface DocumentScan {

    // Cancels a started scan and returns a Promise that resolves with a CancelScanResponse object. If a callback is used, the object is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun cancelScan(
        // The handle of an active scan job previously returned from a call to startScan.
        job: String,
        callback: Value1Function<CancelScanResponse>? = null
    ): Promise<CancelScanResponse>

    // Closes the scanner with the passed in handle and returns a Promise that resolves with a CloseScannerResponse object. If a callback is used, the object is passed to it instead. Even if the response is not a success, the supplied handle becomes invalid and should not be used for further operations.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun closeScanner(
        // Specifies the handle of an open scanner that was previously returned from a call to openScanner.
        scannerHandle: String,
        callback: Value1Function<CloseScannerResponse>? = null
    ): Promise<CloseScannerResponse>

    // Gets the group names and member options from a scanner previously opened by openScanner. This method returns a Promise that resolves with a GetOptionGroupsResponse object. If a callback is passed to this function, returned data is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun getOptionGroups(
        // The handle of an open scanner returned from a call to openScanner.
        scannerHandle: String,
        callback: Value1Function<GetOptionGroupsResponse>? = null
    ): Promise<GetOptionGroupsResponse>

    // Gets the list of available scanners and returns a Promise that resolves with a GetScannerListResponse object. If a callback is passed to this function, returned data is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun getScannerList(
        // A DeviceFilter indicating which types of scanners should be returned.
        filter: DeviceFilter,
        callback: Value1Function<GetScannerListResponse>? = null
    ): Promise<GetScannerListResponse>

    // Opens a scanner for exclusive access and returns a Promise that resolves with an OpenScannerResponse object. If a callback is passed to this function, returned data is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun openScanner(
        // The ID of a scanner to be opened. This value is one returned from a previous call to getScannerList.
        scannerId: String,
        callback: Value1Function<StartScanResponse>? = null
    ): Promise<OpenScannerResponse>

    // Reads the next chunk of available image data from an active job handle, and returns a Promise that resolves with a ReadScanDataResponse object. If a callback is used, the object is passed to it instead.
    //
    //**Note:**It is valid for a response result to be SUCCESS with a zero-length data member. This means the scanner is still working but does not yet have additional data ready. The caller should wait a short time and try again.
    //
    //When the scan job completes, the response will have the result value of EOF. This response may contain a final non-zero data member.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun readScanData(
        // Active job handle previously returned from startScan.
        job: String,
        callback: Value1Function<ReadScanDataResponse>? = null
    ): Promise<ReadScanDataResponse>

    // Performs a document scan and returns a Promise that resolves with a ScanResults object. If a callback is passed to this function, the returned data is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun scan(
        // An object containing scan parameters.
        options: ScanOptions,
        callback: Value1Function<ScanResults>? = null
    ): Promise<ScanResults>

    // Sets options on the specified scanner and returns a Promise that resolves with a SetOptionsResponse object containing the result of trying to set every value in the order of the passed-in OptionSetting object. If a callback is used, the object is passed to it instead.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun setOptions(
        // The handle of the scanner to set options on. This should be a value previously returned from a call to openScanner.
        scannerHandle: String,
        // A list of OptionSetting objects to be applied to the scanner.
        options: List<OptionSetting>,
        callback: Value1Function<SetOptionsResponse>? = null
    ): Promise<SetOptionsResponse>

    // Starts a scan on the specified scanner and returns a Promise that resolves with a StartScanResponse. If a callback is used, the object is passed to it instead. If the call was successful, the response includes a job handle that can be used in subsequent calls to read scan data or cancel a scan.
    @ChromeMinVersion(125)
    @PromiseStyleMinVersion(96)
    fun startScan(
        // The handle of an open scanner. This should be a value previously returned from a call to openScanner.
        scannerHandle: String,
        // A StartScanOptions object indicating the options to be used for the scan. The StartScanOptions.format property must match one of the entries returned in the scanner's ScannerInfo.
        options: StartScanOptions,
        callback: Value1Function<StartScanResponse>? = null
    ): Promise<StartScanResponse>

    data class CancelScanResponse(
        // Provides the same job handle that was passed to cancelScan().
        @ChromeMinVersion(125)
        var job: String,
        // The backend's cancel scan result. If the result is OperationResult.SUCCESS or OperationResult.CANCELLED, the scan has been cancelled and the scanner is ready to start a new scan. If the result is OperationResult.DEVICE_BUSY , the scanner is still processing the requested cancellation; the caller should wait a short time and try the request again. Other result values indicate a permanent error that should not be retried.
        var result: OperationResult,
    )

    // The result of closing the scanner. Even if this value is not SUCCESS, the handle will be invalid and should not be used for any further operations.
    data class CloseScannerResponse(
        @ChromeMinVersion(125)
        var result: OperationResult,
        // The same scanner handle as was passed to closeScanner.
        var scannerHandle: String,
    )

    @ChromeMinVersion(125)
    enum class Configurability {
        // The option is read-only.
        NOT_CONFIGURABLE,

        // The option can be set in software.
        SOFTWARE_CONFIGURABLE,

        // The option can be set by the user toggling or pushing a button on the scanner.
        HARDWARE_CONFIGURABLE,
    }

    // Indicates how the scanner is connected to the computer.
    @ChromeMinVersion(125)
    enum class ConnectionType {
        UNSPECIFIED,
        USB,
        NETWORK
    }

    // The data type of constraint represented by an OptionConstraint.
    @ChromeMinVersion(125)
    enum class ConstraintType {
        // The constraint on a range of OptionType.INT values. The min, max, and quant properties of OptionConstraint will be long, and its list propety will be unset.
        INT_RANGE,

        // The constraint on a range of OptionType.FIXED values. The min, max, and quant properties of OptionConstraint will be double, and its list property will be unset.
        FIXED_RANGE,

        // The constraint on a specific list of OptionType.INT values. The OptionConstraint.list property will contain long values, and the other properties will be unset.
        INT_LIST,

        // The constraint on a specific list of OptionType.FIXED values. The OptionConstraint.list property will contain double values, and the other properties will be unset.
        FIXED_LIST,

        // The constraint on a specific list of OptionType.STRING values. The OptionConstraint.list property will contain DOMString values, and the other properties will be unset.
        STRING_LIST,

    }

    @ChromeMinVersion(125)
    data class DeviceFilter(
        // Only return scanners that are directly attached to the computer.
        var local: Boolean?,
        // Only return scanners that use a secure transport, such as USB or TLS.
        var secure: Boolean?
    )

    @ChromeMinVersion(125)
    data class GetOptionGroupsResponse(
        // If result is SUCCESS, provides a list of option groups in the order supplied by the scanner driver.
        var groups: OptionGroup,
        // The result of getting the option groups. If the value of this is SUCCESS, the groups property will be populated.
        var result: OperationResult,
        // The same scanner handle as was passed to getOptionGroups.
        var scannerHandle: String,
    )

    @ChromeMinVersion(125)
    data class GetScannerListResponse(
        // The enumeration result. Note that partial results could be returned even if this indicates an error.
        var result: OperationResult,
        // A possibly-empty list of scanners that match the provided DeviceFilter.
        var scanners: List<ScannerInfo>,
    )

    @ChromeMinVersion(125)
    data class OpenScannerResponse(
        // If result is SUCCESS, provides a key-value mapping where the key is a device-specific option and the value is an instance of ScannerOption.
        var options: JSObject,
        // The result of opening the scanner. If the value of this is SUCCESS, the scannerHandle and options properties will be populated.
        var result: OperationResult,
        // If result is SUCCESS, a handle to the scanner that can be used for further operations.
        var scannerHandle: String?,
        // The scanner ID passed to openScanner().
        var scannerId: String
    )

    // An enum that indicates the result of each operation.
    @ChromeMinVersion(125)
    enum class OperationResult {
        // An unknown or generic failure occurred.
        UNKNOWN,

        // The operation succeeded.
        SUCCESS,

        // The operation is not supported.
        UNSUPPORTED,

        // The operation was cancelled.
        CANCELLED,

        // The device is busy.
        DEVICE_BUSY,

        // Either the data or an argument passed to the method is not valid.
        INVALID,

        // The supplied value is the wrong data type for the underlying option.
        WRONG_TYPE,

        // No more data is available.
        EOF,

        // The document feeder is jammed.
        ADF_JAMMED,

        // The document feeder is empty.
        ADF_EMPTY,

        // The flatbed cover is open.
        COVER_OPEN,

        // An error occurred while communicating with the device.
        IO_ERROR,

        // The device requires authentication.
        ACCESS_DENIED,

        // Not enough memory is available on the Chromebook to complete the operation.
        NO_MEMORY,

        // The device is not reachable.
        UNREACHABLE,

        // The device is disconnected.
        MISSING,

        // An error has occurred somewhere other than the calling application.
        INTERNAL_ERROR
    }

    @ChromeMinVersion(125)
    data class OptionConstraint(
        var list: List<StringOrNumber>?,
        var max: Number?,
        var min: Number?,
        var quant: Number?,
    )

    @ChromeMinVersion(125)
    data class OptionGroup(
        // An array of option names in driver-provided order.
        var members: List<String>,
        // Provides a printable title, for example "Geometry options".
        var title: String,
    )

    @ChromeMinVersion(125)
    data class OptionSetting(
        // Indicates the name of the option to set.
        var name: String,
        // Indicates the data type of the option. The requested data type must match the real data type of the underlying option.
        var type: OptionType,
        // Indicates the value to set. Leave unset to request automatic setting for options that have autoSettable enabled. The data type supplied for value must match type.
        var value: StrNumBoolOrNumArr?
    )


    @ChromeMinVersion(125)
    enum class OptionType {
        // The option's data type is unknown. The value property will be unset.
        UNKNOWN,

        // The value property will be one of truefalse.
        BOOL,

        // A signed 32-bit integer. The value property will be long or long[], depending on whether the option takes more than one value.
        INT,

        // A double in the range -32768-32767.9999 with a resolution of 1/65535. The value property will be double or double[] depending on whether the option takes more than one value. Double values that can't be exactly represented will be rounded to the available range and precision.
        FIXED,

        // A sequence of any bytes except NUL ('\0'). The value property will be a DOMString.
        STRING,

        // An option of this type has no value. Instead, setting an option of this type causes an option-specific side effect in the scanner driver. For example, a button-typed option could be used by a scanner driver to provide a means to select default values or to tell an automatic document feeder to advance to the next sheet of paper.
        BUTTON,

        // Grouping option. No value. This is included for compatibility, but will not normally be returned in ScannerOption values. Use getOptionGroups() to retrieve the list of groups with their member options.
        GROUP,
    }

    @ChromeMinVersion(125)
    enum class OptionUnit {
        // The value is a unitless number. For example, it can be a threshold.
        UNITLESS,

        // The value is a number of pixels, for example, scan dimensions.
        PIXEL,

        // The value is the number of bits, for example, color depth.
        BIT,

        // The value is measured in millimeters, for example, scan dimensions.
        MM,

        // The value is measured in dots per inch, for example, resolution.
        DPI,

        // The value is a percent, for example, brightness.
        PERCENT,

        // The value is measured in microseconds, for example, exposure time.
        MICROSECOND
    }

    @ChromeMinVersion(125)
    data class ReadScanDataResponse(
        // If result is SUCCESS, contains the next chunk of scanned image data. If result is EOF, contains the last chunk of scanned image data.
        var data: ArrayBuffer?,
        // If result is SUCCESS, an estimate of how much of the total scan data has been delivered so far, in the range 0 to 100.
        var estimatedCompletion: Number?,
        // Provides the job handle passed to readScanData().
        var job: String,
        // The result of reading data. If its value is SUCCESS, then data contains the next (possibly zero-length) chunk of image data that is ready for reading. If its value is EOF, the data contains the last chunk of image data.
        var result: OperationResult,
    )

    @ChromeMinVersion(125)
    data class ScannerInfo(
        // Indicates how the scanner is connected to the computer.
        var connectionType: ConnectionType,
        // For matching against other ScannerInfo entries that point to the same physical device.
        var deviceUuid: String,
        // An array of MIME types that can be requested for returned scans.
        var imageFormats: List<String>,
        // The scanner manufacturer.
        var manufacturer: String,
        // The scanner model if it is available, or a generic description.
        var model: String,
        // A human-readable name for the scanner to display in the UI.
        var name: String,
        // A human-readable description of the protocol or driver used to access the scanner, such as Mopria, WSD, or epsonds. This is primarily useful for allowing a user to choose between protocols if a device supports multiple protocols.
        var protocolType: String,
        // The ID of a specific scanner.
        var scannerId: String,
        // If true, the scanner connection's transport cannot be intercepted by a passive listener, such as TLS or USB.
        var secure: String,
    )

    @ChromeMinVersion(125)
    data class ScannerOption(
        // Indicates whether and how the option can be changed.
        var configurability: Configurability,
        // Defines OptionConstraint on the current scanner option.
        var constraint: OptionConstraint?,
        // A longer description of the option.
        var description: String,
        // Indicates the option is active and can be set or retrieved. If false, the value property will not be set.
        var isActive: Boolean,
        // Indicates that the UI should not display this option by default.
        var isAdvanced: Boolean,
        // Can be automatically set by the scanner driver.
        var isAutoSettable: Boolean,
        // Indicates that this option can be detected from software.
        var isDetectable: Boolean,
        // Emulated by the scanner driver if true.
        var isEmulated: Boolean,
        // The option name using lowercase ASCII letters, numbers, and dashes. Diacritics are not allowed.
        var name: String,
        // A printable one-line title.
        var title: String,
        // The data type contained in the value property, which is needed for setting this option.
        var type: OptionType,
        // The unit of measurement for this option.
        var unit: OptionUnit,
        // The current value of the option, if relevant. Note that the data type of this property must match the data type specified in type.
        var value: StrNumBoolOrNumArr?,
    )

    @ChromeMinVersion(125)
    data class ScanOptions(
        // The number of scanned images allowed. The default is 1.
        var maxImages: Number? = 1,
        // The MIME types that are accepted by the caller.
        var mimeTypes: List<String>?
    )


    data class ScanResults(
        // An array of data image URLs in a form that can be passed as the "src" value to an image tag.
        var dataUrls: List<String>,
        // The MIME type of the dataUrls.
        var mimeTypes: List<String>
    )

    @ChromeMinVersion(125)
    data class SetOptionResult(
        // Indicates the name of the option that was set.
        var name: String,
        // Indicates the result of setting the option.
        var result: OperationResult,
    )

    @ChromeMinVersion(125)
    data class SetOptionsResponse(
        // An updated key-value mapping from option names to ScannerOption values containing the new configuration after attempting to set all supplied options. This has the same structure as the options property in OpenScannerResponse.
        //
        //This property will be set even if some options were not set successfully, but will be unset if retrieving the updated configuration fails (for example, if the scanner is disconnected in the middle of scanning).
        var options: JSObject,
        // An array of results, one each for every passed-in OptionSetting.
        var results: List<SetOptionResult>,
        // Provides the scanner handle passed to setOptions().
        var scannerHandle: String,
    )

    @ChromeMinVersion(125)
    data class StartScanOptions(
        // Specifies the MIME type to return scanned data in.
        var format: String,
        // If a non-zero value is specified, limits the maximum scanned bytes returned in a single readScanData response to that value. The smallest allowed value is 32768 (32 KB). If this property is not specified, the size of a returned chunk may be as large as the entire scanned image.
        var maxReadSize: Number?,
    )

    @ChromeMinVersion(125)
    data class StartScanResponse(
        // If result is SUCCESS, provides a handle that can be used to read scan data or cancel the job.
        var job: String?,
        // The result of starting a scan. If the value of this is SUCCESS, the job property will be populated.
        var result: OperationResult,
        // Provides the same scanner handle that was passed to startScan().
        var scannerHandle: String,
    )

}